Skip to content

yieldAll through nested iterators #8

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed

Conversation

h0tk3y
Copy link
Contributor

@h0tk3y h0tk3y commented Oct 24, 2016

Partial solution for #7 -- implementation of yieldAll and recursive generators through SpecSharp nested iterators.

Considerations:

  • Needs performance measurement against original implementation (and, probably, extraction into separate API if this turns out to be considerably slower)

  • Increased allocation overhead by one object per iterator: RootIterator is allocated when iterating over the generated sequence (negligible?)

  • Probably some optimizations are possible that simplify the iterator behavior in cases when there were no yieldAll calls up to some point

  • Tail recursion can be optimized, but not in a transparent way. One option is to add separate function generateWithTail (or something) that would take a coroutine returning Sequence<T>

    fun fromTo(from: Int, to: Int): Sequence<Int> = generateWithTail f@{
       if (from > to) return@f emptySequence()
       yield(from)
       return@f fromTo(from + 1, to)
    }
    

    Another option is to request a coroutines API that would allow one to find out that a Continuation<Unit> is basically a NOP that will do nothing but immediately finish the coroutine block. Once we know this about continuations we can easily optimize tail recursion.

Added tests for yieldAll to GenerateTest.kt
…n-us/research/wp-content/uploads/2016/02/specsharp-iterators.pdf.

Added yieldAll for Sequence (including nested `generate`), Iterable and vararg.
Added tests for yieldAll.
@h0tk3y
Copy link
Contributor Author

h0tk3y commented Nov 21, 2016

Unfortunately, this implementations seems to be about two times slower than original generate. Benchmark: (link), see the benchmarks suffixed by n. Any optimization suggestions?

My results:

Benchmark                                  Mode  Cnt     Score    Error  Units
SequenceCoroutineOperations.filter_ai      avgt   40   712.893 ±  8.580  us/op
SequenceCoroutineOperations.filter_c       avgt   40  1035.318 ± 11.017  us/op
SequenceCoroutineOperations.filter_ci      avgt   40   965.898 ± 25.101  us/op
SequenceCoroutineOperations.filter_cin     avgt   40  1811.378 ± 56.751  us/op
SequenceCoroutineOperations.filter_cn      avgt   40  1940.069 ± 44.974  us/op
SequenceCoroutineOperations.filter_std     avgt   40   511.533 ±  4.832  us/op
SequenceCoroutineOperations.filter_std_ai  avgt   40   761.549 ±  2.216  us/op
SequenceCoroutineOperations.map            avgt   40  1071.858 ± 12.418  us/op
SequenceCoroutineOperations.map_c          avgt   40  2590.374 ± 28.339  us/op
SequenceCoroutineOperations.map_ci         avgt   40  3086.386 ± 15.886  us/op
SequenceCoroutineOperations.map_cin        avgt   40  3497.331 ± 44.871  us/op
SequenceCoroutineOperations.map_cn         avgt   40  4274.558 ± 53.390  us/op

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant